1. User 영역에서 Kernel로의 데이터 흐름

  • 애플리케이션(User Data 영역)에서 파일 입출력 함수를 호출하면, 바로 디스크에 쓰는 것이 아니라 File Driver(파일 드라이버) 계층을 거쳐 Kernel로 진입합니다.

  • 데이터 전달 계층:

    • 유저 애플리케이션 코드 (printf, fopen, fread 등)
    • C 표준 라이브러리 (I/O Buffer 관리)
    • 시스템 콜 (read, write 등)
    • VFS(가상 파일 시스템) 및 파일 드라이버 (NTFS, EXT4 등)
    • OS 커널 페이지 캐시(Page Cache) 및 블록 디바이스 드라이버
    • 물리 디스크(SSD, HDD) / 터미널 장치

2. 콘솔 입출력과 파일 I/O의 관계 (“모든 것은 파일이다”)

  • printf, scanf, gets_s, puts 등 콘솔 입출력 함수는 새로운 기술이 아니며, 프로그램 구동 시 OS가 기본적으로 열어두는 표준 스트림(stdin, stdout)을 사용하는 파일 I/O와 완전히 동일한 구조입니다.

    • stdin (표준 입력, FD 0): 읽기 전용 콘솔 입력 (키보드 매핑)
    • stdout (표준 출력, FD 1): 쓰기 전용 콘솔 출력 (모니터 매핑)
    • stderr (표준 에러, FD 2): 버퍼링 없이 즉시 출력되는 에러 스트림
  • “CON” 디바이스 파일 (Windows 기준)

    • 파일 경로에 "CON"을 지정하면 콘솔 화면/키보드를 직접 파일로 열 수 있습니다.
    • fopen("CON", "r"): 콘솔 키보드 입력을 읽기 전용으로 오픈 (stdin과 동일)
    • fopen("CON", "w"): 콘솔 화면 출력을 쓰기 전용으로 오픈 (stdout과 동일)
    • 주의점: "CON" 파일은 읽기와 쓰기("r+" 등)를 동시에 열 수 없으며, 시도 시 드라이버 충돌로 인해 오류가 발생합니다. (POSIX/리눅스 환경은 "/dev/tty" 매핑)

3. FILE 인터페이스의 Page 단위(4KB) 버퍼링

  • FILE 구조체를 통한 표준 I/O는 시스템 콜의 잦은 호출로 인한 오버헤드를 줄이기 위해, OS 메모리 관리 최소 단위인 Page 단위(기본 4KB)의 버퍼를 유저 공간에 할당하여 읽고 씁니다.

  • 버퍼링 3가지 모드 (setvbuf 설정 가능)

    1. 완전 버퍼링 (_IOFBF): 일반 디스크 파일. 4KB 버퍼가 꽉 차거나 닫힐 때만 디스크 I/O 실행
    2. 행 단위 버퍼링 (_IOLBF): stdout. 개행 문자(\n)를 만나거나 버퍼가 찰 때 방출
    3. 무버퍼 (_IONBF): stderr. 버퍼를 거치지 않고 즉각 전달

4. fflush() 함수의 용도와 주의사항

  • 역할: 출력 버퍼(Output Buffer)에 쌓여 있는 데이터를 물리 디스크나 화면으로 즉시 강제 방출(비우기)합니다.

  • 주의사항:

    • 예전 일부 구형 컴파일러에서 입력 버퍼를 비우기 위해 fflush(stdin)을 사용했으나, C 표준(C99/C11) 규격상 입력 스트림에 대한 fflush()는 “정의되지 않은 동작(Undefined Behavior)“입니다.
    • 따라서 fflush출력 스트림에만 사용해야 합니다.

표준 입력 버퍼 비우기 패턴:

int c;
while ((c = getchar()) != '\n' && c != EOF);